<template>
  <div v-loading="loading">
    <el-form class="query-table-form" @submit.native.prevent :inline="true" :model="params">
      <el-form-item>
        <select-address
          v-model="params.address_code"
          placeholder="地址查询"
          :auto-top="1"
          clearable
          @change="loadData()"
        ></select-address>
      </el-form-item>
      <el-form-item>
        <el-input
          v-model="params.agency_name"
          placeholder="银行名称查询"
          :clearable="true"
          @keyup.enter.native="loadData()"
        ></el-input>
      </el-form-item>
      <el-form-item>
        <select-system-enum
          placeholder="银行类型"
          type="bankClass"
          clearable
          @change="loadData()"
          v-model="params['agency_type_sub.eq']"
        ></select-system-enum>
      </el-form-item>

      <el-form-item>
        <el-button icon="el-icon-search" @click="loadData()">查询</el-button>
      </el-form-item>
    </el-form>

    <div class="bank-cascader__tags">
      <span v-if="!presentNodes.length" class="bank-cascader__hint">请选择合作机构：</span>
      <span v-else class="bank-cascader__clear">
        <i class="el-icon-circle-close" @click.stop="clearCheckedNodes"></i>
      </span>
      <el-tag
        v-for="node in presentNodes"
        :key="node.uid"
        type="info"
        disable-transitions
        :closable="true"
        @close="deleteNode(node)"
      >
        <span>{{ node.label }}</span>
      </el-tag>
    </div>
    <el-cascader-panel
      class="bank-cascader__panel"
      ref="bankCascaderPanel"
      v-model="innerValue"
      :options="options"
      :props="props"
      @change="handleOnChange"
    >
      <div
        slot-scope="{ node, data }"
        @click="e => handleLabelClick(e, node, data)"
        class="bank-cascader__item"
        :class="data.disabled && 'is-disabled'"
      >
        <div class="bank-cascader__checkbox" :class="node.checked && 'is-checked'"></div>
        <div class="bank-cascader__label">
          <div class="bank-cascader__label-name">{{ data.agency_name }}</div>
          <small class="bank-cascader__label-address" v-if="!data.isAll">
            {{ data.address || '-' }}
          </small>
        </div>
      </div>
    </el-cascader-panel>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import { cascaderParse, cascaderFind, cascaderFindAll, guid } from '@vimi/utils-tool'
import SelectAddress from '@/components/select/SelectAddress'
import SelectSystemEnum from '@/cadmin/components/select/SelectSystemEnum'
const isEqual = (a, b) => {
  if (Array.isArray(a) && Array.isArray(b)) {
    if (a.length !== b.length) {
      return false
    }

    for (let i = 0; i < a.length; i++) {
      if (Array.isArray(a[i])) {
        if (!isEqual(a[i], b[i])) {
          return false
        }
      } else if (a[i] !== b[i]) {
        return false
      }
    }

    return true
  }

  return a === b
}

export default {
  components: {
    SelectAddress,
    SelectSystemEnum,
  },
  props: {
    value: {
      type: [Array, String],
    },
    disabledNode: Array,
    topValue: String,
  },
  model: {
    prop: 'value',
    event: 'change',
  },
  data() {
    return {
      options: [],
      props: {
        label: 'agency_name',
        value: 'agency_id',
        multiple: true,
        checkStrictly: true,
        emitPath: false,
      },
      loading: false,
      emitChange: false,
      presentNodes: [],
      innerValue: [],
      oldDisabled: [],
      params: {},
    }
  },
  computed: {
    ...mapGetters(['allAccessBankAgency']),
    bankOptions() {
      const options = cascaderParse({
        data: this.allAccessBankAgency,
        key: 'agency_code',
        parentKey: 'parent_code',
        checkParent: true,
      })
      this.addAllRadioItem(options)
      return options
    },
    panel() {
      return this.$refs.bankCascaderPanel
    },
    leafOnly() {
      return !this.props.checkStrictly
    },
    isArrayValue() {
      return Array.isArray(this.value)
    },
  },
  watch: {
    value: {
      handler: function (val) {
        if (this.emitChange) {
          this.emitChange = false
          return
        }

        this.loadData().then(() => {
          const value = this.isArrayValue ? val : (val || '').split(',')
          const checkedValue = this.getCheckedValue(value)
          if (!isEqual(checkedValue, this.innerValue)) {
            this.innerValue = checkedValue
            this.computePresentContent()
          }
        })
      },
      deep: true,
      immediate: true,
    },
    disabledNode: {
      handler: function (newVal, oldVal) {
        this.oldDisabled = oldVal || []
        this.doDisableItem()
      },
      deep: true,
      immediate: true,
    },
    topValue: {
      handler: function () {
        this.$nextTick(() => {
          this.panel.activePath = []
          this.clearCheckedNodes()
          this.options = this.doTopValue()
        })
      },
      immediate: true,
    },
  },
  created() {},
  mounted() {},
  methods: {
    loadData() {
      this.loading = true
      return this.$store
        .dispatch('getAllAccessBankAgency', this.params)
        .then(() => {
          this.doDisableItem()
          this.options = this.doTopValue()
        })
        .finally(() => {
          this.loading = false
        })
    },
    // 递归添加全选项
    addAllRadioItem(list) {
      list.unshift({
        agency_name: '全选',
        address: '',
        agency_id: guid(),
        isAll: true,
      })
      for (const item of list) {
        if (item.children && item.children.length) {
          this.addAllRadioItem(item.children)
        }
      }
    },
    // 禁用选择
    doDisableItem() {
      if (!this.bankOptions.length) return
      this.disableItems(this.oldDisabled, false)
      this.disableItems(this.disabledNode, true)
    },
    disableItems(disabledList = [], disabled = true) {
      const { bankOptions } = this
      const disableds = [...disabledList]
      while (disableds.length > 0) {
        const first = disableds.shift()
        const node = cascaderFind(bankOptions, it => it.agency_id === first)
        if (node) node.disabled = disabled
      }
    },
    // 顶级银行id,只选择其子级银行
    doTopValue() {
      const { bankOptions } = this
      if (!this.topValue) return bankOptions
      const node = cascaderFind(bankOptions, it => it.agency_id === this.topValue)
      return (node && node.children) || []
    },
    handleOnChange() {
      this.emitChange = true

      const checkedNodes = this.getCheckedNodes()
      this.presentNodes = checkedNodes.filter(node => !node.data.isAll)
      const value = this.presentNodes.map(({ value }) => {
        return Array.isArray(value) ? value[value.length - 1] : value
      })
      this.$emit('change', this.isArrayValue ? value : value.join(','), this.presentNodes)
    },
    handleLabelClick(e, node, data) {
      if (data.disabled) return
      const { checked } = node
      const menuNodes = this.getAllMenuNodes(node)
      const isClickCheckbox = e.target.className.includes('bank-cascader__checkbox')
      if (data.isAll) {
        // 如果是全选，切换列表所有item的状态
        menuNodes.forEach(it => {
          if (!it.data.disabled) {
            it.doCheck(!checked)
          }
        })
        this.panel.calculateMultiCheckedValue()
      } else if (isClickCheckbox || !node.hasChildren) {
        // 如果没有children，切换选择状态
        node.doCheck(!checked)
        this.checkAllStatus(checked, menuNodes)
        this.panel.calculateMultiCheckedValue()
      }
    },
    // 删除选中node
    deleteNode(node) {
      node.doCheck(false)
      this.checkAllStatus(true, this.getAllMenuNodes(node))
      this.panel.calculateMultiCheckedValue()
    },
    // 获取当前级别所有node
    getAllMenuNodes(node) {
      const { level, parent } = node
      const nodes = this.panel.getFlattedNodes(this.leafOnly)
      return nodes.filter(it => it.level === level && it.parent === parent)
    },
    // 判断更新全选状态
    checkAllStatus(checked, menuNodes) {
      const nodeAllIndex = menuNodes.findIndex(it => it.data.isAll)
      const nodeAll = menuNodes.splice(nodeAllIndex, 1)[0]
      if (!checked) {
        const isAllChecked = menuNodes.every(node => node.checked)
        if (isAllChecked) {
          nodeAll.doCheck(true)
        }
      } else {
        const hasNoChecked = menuNodes.some(node => !node.checked)
        if (hasNoChecked) {
          nodeAll.doCheck(false)
        }
      }
    },
    // 平级计算成多层选中值
    getCheckedValue(value) {
      const checkedValue = []
      const checkedAll = []
      for (const val of value) {
        const bank = this.allAccessBankAgency.find(bank => bank.agency_id === val)
        if (bank) {
          const arr = cascaderFindAll(this.options, t => t.agency_code === bank.agency_code)
          const len = arr.length
          if (this.props.emitPath) {
            checkedValue.push(len > 1 ? arr.map(it => it.agency_id) : val)
          } else {
            checkedValue.push(val)
          }

          // 初始化全选状态
          let sameLevelNode = []
          let parentId = ''
          if (len > 1) {
            const parent = arr[len - 2]
            sameLevelNode = [...parent.children]
            parentId = parent.agency_id
          } else {
            sameLevelNode = [...this.options]
            parentId = 'all'
          }
          if (!checkedAll.includes(parentId)) {
            checkedAll.push(parentId)
            const allIndex = sameLevelNode.findIndex(it => it.isAll)
            if (allIndex > -1) {
              const allOption = sameLevelNode.splice(allIndex, 1)[0]
              const isAllChecked = sameLevelNode.every(it => value.includes(it.agency_id))
              if (isAllChecked) {
                checkedValue.push(allOption.agency_id)
              }
            }
          }
        }
      }
      return checkedValue
    },
    // 计算当前选中值
    computePresentContent() {
      this.$nextTick(() => {
        const checkedNodes = this.getCheckedNodes()
        this.presentNodes = checkedNodes.filter(node => !node.data.isAll)
      })
    },
    getCheckedNodes() {
      return this.panel.getCheckedNodes(this.leafOnly)
    },
    clearCheckedNodes() {
      return this.panel.clearCheckedNodes()
    },
  },
}
</script>

<style lang="scss" scoped>
/deep/ .bank-cascader__panel {
  .el-cascader-menu__wrap {
    height: 60vh;
    min-height: 360px;
  }
  .el-cascader-node {
    height: auto;
    min-height: 34px;
    line-height: 1.428;
    padding-top: 2px;
    padding-bottom: 2px;

    .el-checkbox {
      display: none;
    }
  }
  .bank-cascader__label-name {
    white-space: normal;
  }
  .bank-cascader__label-address {
    display: inline-block;
    color: $gray-600;
    width: 100%;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
  }
}

.bank-cascader__item {
  display: flex;
  align-items: center;
  position: relative;
  &.is-disabled {
    cursor: not-allowed;
    .bank-cascader__checkbox {
      background-color: var(--primary-transparent-1);
      border-color: var(--primary-transparent-2);
    }
    .bank-cascader__label,
    .bank-cascader__label-address {
      color: #c0c4cc;
    }
  }
}
.bank-cascader__label {
  flex: 1;
  width: 100%;
  padding-left: calc(14px + 1rem);
}
.bank-cascader__checkbox {
  width: 14px;
  height: 14px;
  margin-right: 1rem;
  border: 1px solid $border-color;
  border-radius: 2px;
  position: absolute;
  background-color: #fff;
  transition: border-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46),
    background-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46);
  &.is-checked {
    border-color: $primary;
    border-color: var(--primary);
    background-color: $primary;
    background-color: var(--primary);
    &::after {
      transform: rotate(45deg) scaleY(1);
    }
  }
  &::after {
    box-sizing: content-box;
    content: '';
    border: 1px solid #fff;
    border-left: 0;
    border-top: 0;
    height: 7px;
    left: 4px;
    position: absolute;
    top: 1px;
    transform: rotate(45deg) scaleY(0);
    width: 3px;
  }
}

.bank-cascader__tags {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  border-radius: 4px;
  border: 1px solid $border-color;
  padding: 3px 40px 3px 10px;
  margin-bottom: 6px;
  min-height: 38px;
  position: relative;
  cursor: pointer;
  .bank-cascader__hint {
    color: $gray-600;
    line-height: 32px;
  }
  .el-tag {
    display: inline-block;
    align-items: center;
    margin: 2px 0 2px 6px;
    text-overflow: ellipsis;
    background: #f0f2f5;
  }
}
.bank-cascader__clear {
  position: absolute;
  right: 10px;
  color: $gray-600;
  &:hover {
    color: #333;
  }
}
</style>
